namespace NRank.Common
{
	/// <summary>
	/// IRanked implementation and extensions.
	/// </summary>
	public static class Ranked
	{
		/// <summary>
		/// Creates instance of IRanked interface wrapping given object and having given rank
		/// </summary>
		/// <typeparam name="T">Type of wrapped object</typeparam>
		/// <param name="obj">Wrapped object</param>
		/// <param name="rank">Object's rank</param>
		/// <returns></returns>
		public static IRanked<T> New<T>(T obj, double rank)
		{
			return new RankedImpl<T>(obj, rank);
		}

		/// <summary>
		/// Extension method for converting any object to ranked object
		/// </summary>
		/// <typeparam name="T">Type of wrapped object</typeparam>
		/// <param name="obj">Wrapped object</param>
		/// <param name="rank">Object's rank</param>
		/// <returns></returns>
		public static IRanked<T> AsRanked<T>(this T obj, double rank)
		{
			return New(obj, rank);
		}

		/// <summary>
		/// Private implementation of IRanked
		/// </summary>
		/// <typeparam name="T">Type of wrapped object</typeparam>
		private struct RankedImpl<T> : IRanked<T>
		{
			/// <summary>
			/// Wrapped object
			/// </summary>
			public T Object { get; private set; }

			/// <summary>
			/// Object's rank
			/// </summary>
			public double Rank { get; private set; }

			/// <summary>
			/// Creates instance of RankedImpl
			/// </summary>
			/// <param name="obj">Wrapped object</param>
			/// <param name="rank">Object's rank</param>
			public RankedImpl(T obj, double rank)
				: this()
			{
				Object = obj;
				Rank = rank;
			}

			/// <summary>
			/// Compares ranked object with other ranked object by comparing their ranks
			/// </summary>
			/// <param name="other">Object to compare</param>
			/// <returns>Objects' order</returns>
			public int CompareTo(IRanked<T> other)
			{
				return this.Rank.CompareTo(other.Rank);
			}

			/// <summary>
			/// Compares ranked object with any other object
			/// </summary>
			/// <param name="obj">Other object to compare</param>
			/// <returns>Order of objects</returns>
			public int CompareTo(object obj)
			{
				return CompareTo((IRanked<T>)obj);
			}

			/// <summary>
			/// Provides readable information about ranked object
			/// </summary>
			/// <returns>Readable information about ranked object</returns>
			public override string ToString()
			{
				return string.Format("{0} {1}", this.Rank, this.Object);
			}
		}
	}
}